<template>
  <el-form ref="keywordForm" :model="formData" :disabled="loading" @submit.prevent class="search-form" v-if="props.type === 'custom' || (props.crudRef && props.crudRef.option)">
    <div class="search-container" >
      <div class="search-input-wrap">
        <el-form-item prop="q">
          <el-tooltip
            :visible="keywordSearchColumn.length > 0 && keywordTipsVisible"
            placement="top"
            :content="`支持关键字：${keywordSearchColumn.map(i => i.label).join('、')}`"
          >
            <el-input
              class="search-input append-input"
              v-model="formData.q"
              :placeholder="$attrs.placeholder || `输入${props.label}搜索`"
              clearable
              :size="$attrs.size"
              :disabled="loading"
              :style="`${$attrs.inputStyle}`"
              @focus="keywordTipsVisible = true"
              @blur="keywordTipsVisible = false"
              @keyup.enter="onKeywordSubmit"
            >
              <template #append>
                <el-button
                  type="primary"
                  icon="Search"
                  class="search-trigger"
                  :size="$attrs.size"
                  :loading="loading"
                  :disabled="loading"
                  @click="onKeywordSubmit"
                >{{$attrs.searchText || '搜索'}}</el-button>
              </template>
            </el-input>
          </el-tooltip>
        </el-form-item>
      </div>
      <div class="search-filter-wrap">
        <el-popover
          ref="searchFilterPopover"
          placement="bottom"
          :width="500"
          :visible="searchFilterOpen"
          :teleported="false"
          trigger="click"
          popper-class="search-filter-popper"
        >
          <div class="search-filter-popper-header">
            <el-button
              type="info"
              text
              :disabled="loading"
              class="search-filter-popper-close"
              @click="onCloseFilter"
            >
              <el-icon><Close /></el-icon>
            </el-button>
          </div>
          <div class="search-filter-popper-container" v-loading="loading">
            <FilterForm
              ref="searchFilterForm"
              :option="filterOptions"
              v-model="formData"
              @submit="onFilterSubmit"
              class="search-filter-form"
            ></FilterForm>
          </div>
          <div class="search-filter-popper-footer">
            <el-button
              type="primary"
              icon="Search"
              :size="$attrs.size"
              @click="$refs.searchFilterForm.$refs.form.submit()"
            >搜 索</el-button>
            <el-button
              icon="Delete"
              :size="$attrs.size"
              @click="onFilterReset"
            >清 空</el-button>
          </div>
          <template #reference>
            <el-button
              :type="searchFilterOpen ? 'warning':'primary'"
              plain
              :icon="searchFilterOpen ? 'Close':'Filter'"
              class="search-filter-trigger"
              :size="$attrs.size"
              :disabled="loading"
              @click="onOpenFilter"
              v-click-outside="onClickOutside"
              v-if="searchOptions && searchOptions.column.length"
            >
              {{
                searchFilterOpen ? 
                $attrs.filterCloseText || '关闭'
                :
                $attrs.filterText || '筛选'
              }}
              </el-button>
          </template>
        </el-popover>
      </div>
    </div>
  </el-form>
  <div class="search-result-container" v-if="(props.type === 'custom' || (props.crudRef && props.crudRef.option)) && searchResultColumn.length && Object.keys(searchResult).length">
    <div class="search-result-label">当前筛选：</div>
    <div class="search-result-wrap">
      <template v-for="item in searchResultColumn" :key="item.prop">
        <el-tag
          class="search-result-item"
          :closable="true"
          size="small"
          :type="onGetItemTagType(item, searchResult[item.prop])"
          @close="onRemoveFilter(item)"
        >
          <el-tooltip
            trigger="hover"
            placement="top"
            :content="item.label"
          >
            <span>{{searchResult[`$${item.prop}`] || searchResult[item.prop]}}</span>
          </el-tooltip>
        </el-tag>
      </template>
      <div class="search-result-menu" v-if="!loading">
        <el-tooltip
          trigger="hover"
          placement="top"
          content="添加筛选"
        >
          <el-button
            type="primary"
            size="mini"
            icon="Plus"
            class="search-result-menu-item"
            v-if="filterOptions.column.length > 0"
            @click="onOpenFilter"
          >添加</el-button>
        </el-tooltip>
          <el-popconfirm
            :width="200"
            title="是否确认清除筛选？"
            @confirm="onClearFilter"
          >
            <template #reference>
              <el-button
                type="danger"
                size="mini"
                icon="Close"
                class="search-result-menu-item"
              >
                <el-tooltip
                  trigger="hover"
                  placement="top"
                  content="清除筛选"
                >
                  清除
                </el-tooltip>
              </el-button>
            </template>
          </el-popconfirm>
      </div>
    </div>
  </div>  
</template>

<script setup name="CrudSearch">
import dayjs from 'dayjs'
import { ClickOutside as vClickOutside } from "element-plus"
import FilterForm from './FilterForm/index.vue'
import { filterParams } from '@/utils/ruoyi'
const { proxy } = getCurrentInstance();

const modelValue = defineModel()
const emit = defineEmits(['search-change'])
const props = defineProps({
  type: {
    type: String,
    default: 'crud', // crud、custom
  },
  prop: {
    type: String,
    default: 'q'
  },
  label: {
    type: String,
    default: '关键字'
  },
  loading: {
    type: Boolean,
    default: false
  },
  crudRef: {
    type: Object,
    default: () => ({})
  },
  options: {
    type: Array,
    default: () => ({})
  },
  dicData: {
    type: Object,
    default: () => ({})
  }
})
const loading = ref(false)
const searchFilterOpen = ref(false)
const searchFilterPopover = ref(null)
const searchRefs = computed(() => props.crudRef?.$refs?.headerSearch)
const searchOptions = computed(() => searchRefs.value?.option || props.options)
const dicData = computed(() => props.crudRef?.DIC || props.dicData)
const searchColumn = computed(() => searchOptions.value.column)
const keywordSearchColumn = computed(() => searchColumn.value.filter(i => !!i._keywords))
const filterOptions = computed(() => ({
  ...searchOptions.value,
  column: (searchColumn.value || []).map(i => {
    if (i._customValidator && i._customValidator instanceof Function) {
      i.rules = [
        ...(i.searchRules || []),
        { validator: i._customValidator.bind({ form: formData.value }), trigger: 'change' }
      ]
    }
    return {
      ...i,
      span: 24,
      popperClass: 'crud-search-popper'
    }
  }),
  gutter: 0,
  submitBtn: false,
  emptyBtn: false
}))

const formData = ref({
  q: ''
})
const searchResultColumn = ref([])
const searchResult = ref({})
const done = ref(() => {})
const keywordTipsVisible = ref(false)

watch(
  () => props.crudRef?.tableLoading || props.loading,
  (val) => {
    loading.value = val
  }
)

watch(
  () => props.dicData,
  (val) => {
    if (val) {
      Object.keys(val).forEach(prop => {
        proxy.$refs.searchFilterForm.$refs.form.updateDic(prop, val[prop])
      })
    }
  },
  {
    deep: true
  }
)

const onClickOutside = (e) => {
  // 判断是否点击了弹窗里面的下拉组件、日期选择组件
  const isPopperDescendant = (child) => {
    let node = child.parentNode
    while (node) {
      if (node.className && node.className && node.className.indexOf('crud-search-popper') !== -1) {
        return true
      }
      node = node.parentNode
    }
    return false
  }
  if (
    searchFilterOpen.value &&
    !unref(searchFilterPopover).popperRef.contentRef.contains(e.target) &&
    !isPopperDescendant(e.target)
  ) {
    searchFilterOpen.value = false
  }
}

/** 设置筛选结果 */
const onSetSearchResult = () => {
  return new Promise(async (resolve, reject) => {
    try {
      const _column = searchColumn.value
        .filter(i => {
          const hasValue =  !proxy.validatenull(formData.value[i.prop])
          return i.prop && hasValue
        })
        .map(v => {
          const tem = { ...v }
          if (dicData.value[v.prop]) {
            tem.dicData = dicData.value[v.prop]
          }
          return tem
        })
      if (!proxy.validatenull(formData.value['q'])) {
        _column.unshift({
          label: props.label,
          prop: 'q',
          tag_type: 'warning'
        })
      }
      await onSearchResultFormatter(_column)
      searchResultColumn.value = _column
      resolve(true)
    } catch (error) {
      resolve(true)
    }
  })
}

const onGetItemTagType = (item, value) => {
  let tagType = item.tag_type || 'primary'
  if (item.dicData && item.dicData.length) {
    const dicItem = item.dicData.find(i => i.value === value) || {}
    if (dicItem.tag_type) {
      tagType = dicItem.tag_type
    }
  }
  return tagType
}

const onSearchResultFormatter = (column = []) => {
  return new Promise((resolve, reject) => {
    try {
      const { search = {} } = props.crudRef
      const form = {
        ...(search || {}),
        ...modelValue.value,
        ...formData.value
      }
      column.forEach(item => {
        if (item.type && (item.type.indexOf('date') !== -1 || item.type.indexOf('time') !== -1)) {
          if (form[item.prop] instanceof Array) {
            form[item.prop] = form[item.prop].map(i => item.format && dayjs(i).isValid() ? dayjs(i).format(item.format) : i).join('，')
          } else {
            form[item.prop] = item.format && dayjs(form[item.prop]).isValid() ? dayjs(form[item.prop]).format(item.format) : form[item.prop]
          }
        }
      })
      searchResult.value = form
      resolve(true)
    } catch (error) {
      resolve(true)
    }
  })
}

/** 关键字搜索 */
const onKeywordSubmit = () => {
  proxy.$refs.keywordForm.validate()
    .then(() => {
      proxy.$refs.searchFilterForm.$refs.form.validate((valid, error) => {
        if (valid) {
          proxy.$refs.searchFilterForm.$refs.form.submit()
        } else {
          searchFilterOpen.value = true
        }
      })
    })
}

/** 关键字清空 */
const onKeywordReset = () => {
  proxy.$refs.keywordForm.resetFields()
}

/** 筛选搜索 */
const onFilterSubmit = (form, done) => {
  done.value = done
  onSearchChange()
  nextTick(() => {
    done()
  })
}

/** 筛选清空 */
const onFilterReset = () => {
  proxy.$refs.searchFilterForm.$refs.form.resetForm()
}

/** 触发搜索 */
const onSearchChange = () => {
  loading.value = true
  const { q, ...extraFormData } = filterParams(formData.value)
  Object.keys(extraFormData).forEach(item => {
    if (proxy.validatenull(extraFormData[item])) {
      delete extraFormData[item]
    }
  })
  console.log("🚀 ~ Object.keys ~ extraFormData:", extraFormData)
  modelValue.value = {
    ...(extraFormData || {}),
    [props.prop]: q || undefined
  }
  nextTick(async () => {
    props.crudRef &&
    props.crudRef.searchChange &&
    props.crudRef.searchChange instanceof Function &&
    props.crudRef.searchChange(modelValue.value, done.value)
    props.crudRef._searchForm = modelValue.value
    emit("search-change", modelValue.value)
    await onSetSearchResult()
    setTimeout(() => {
      onCloseFilter()
      // loading.value = false
    }, 50);
  })
}

/** 清除筛选 */
const onClearFilter = () => {
  searchResultColumn.value = []
  formData.value = {}
  onFilterReset()
  onKeywordReset()
  nextTick(() => {
    onSearchChange()
  })
}

const onRemoveFilter = (item) => {
  formData.value[item.prop] = ''
  nextTick(() => {
    onSearchChange()
  })
}

/** 打开筛选 */
const onOpenFilter = () => {
  searchFilterOpen.value = !searchFilterOpen.value
}
/** 关闭筛选 */
const onCloseFilter = () => {
  searchFilterOpen.value = false
}
</script>

<style lang="scss" scoped>
.search-form {
  width: 100%;
  display: flex;
  justify-content: center;
}
.search-container {
  display: flex;
  width: 50%;
  max-width: 800px;
  padding: 0 10px;
  .search-input-wrap {
    flex: 1;
    padding: 0 5px;
    .search-input {
      font-size: 16px;
      height: 40px;
    }
  }
  .search-trigger {
    display: flex;
    align-items: center;
    padding: 8px 10px;
  }
  .search-filter-wrap {
    display: flex;
    padding: 0 5px;
  }
  .search-filter-trigger {
    margin-bottom: 22px;
    height: 40px;
    padding: 8px 10px;
  }
}

.search-result-container {
  display: flex;
  align-items: flex-start;
  padding-bottom: 15px;
  .search-result-label {
    width: 80px;
    padding: 4px 0;
    font-size: 15px;
    color: #666666;
  }
  .search-result-wrap {
    display: flex;
    flex-wrap: wrap;
    flex: 1;
    .search-result-item {
      margin: 4px 5px;
      cursor: pointer;
    }
    .search-result-menu {
      padding: 0 10px;
      .search-result-menu-item {
        height: 28px;
        padding: 4px 8px;
        font-size: 12px;
      }
    }
  }
}

@media screen and (min-width: 799px) {
  .search-container {
    width: 550px;
  }
}
@media screen and (max-width: 798px) {
  .search-container {
    width: 80%;
  }
}
@media screen and (max-width: 600px) {
  .search-container {
    width: 90%;
  }
}
@media screen and (max-width: 500px) {
  .search-container {
    width: 100%;
    display: block;
    .search-filter-trigger {
      flex: 1;    
    }
  }
}
</style>
<style lang="scss">
.search-filter-popper {
  display: flex;
  flex-direction: column;
  min-height: 20vh;
  max-height: 70vh;
  box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px!important;
  padding: 0 10px 15px!important;
  .search-filter-popper-header {
    padding: 10px 0;
    .search-filter-popper-close {
      padding: 0 10px;
      font-size: 16px;
      float: right;
    }
  }
  .search-filter-popper-container {
    flex: 1;
    padding: 0 10px;
    overflow-y: auto;
  }
  .search-filter-popper-footer {
    display: flex;
    justify-content: center;
    align-items: center;
    padding-top: 15px;
    border-top: 1px solid #efefef;
  }
}
@media screen and (max-width: 500px) {
  .search-filter-popper {
    width: 90%!important;
  }
}
</style>
